package com.mbiolance.cloud.activiti.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mbiolance.cloud.activiti.domain.dto.ModelDto;
import com.mbiolance.cloud.activiti.domain.dto.ProcessDefinitionDto;
import com.mbiolance.cloud.auth.domain.PageModel;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 流程定义service
 */
@Service
@Slf4j
public class ProcessDefinitionService {

    @Autowired
    private RepositoryService repositoryService;

    /**
     * 部署流程（将流程模型转为流程定义）
     * @param modelId   流程模型id
     */
    public Boolean deploy(String modelId) throws Exception {
        Model modelData = repositoryService.getModel(modelId);
        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
        JsonNode modelNode = new ObjectMapper().readTree(bytes);
        BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
        if (model.getProcesses().size() == 0) {
            log.error("工作流数据模型不符要求，请至少设计一条主线流程！");
        }
        byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
        String processName = modelData.getName() + ".bpmn20.xml";
        Integer version = modelData.getVersion();
        Deployment deploy = repositoryService.createDeployment()
                .name(modelData.getName() + " - " + version)
                .addString(processName, new String(bpmnBytes, StandardCharsets.UTF_8))
                .deploy();
        modelData.setDeploymentId(deploy.getId());
        repositoryService.saveModel(modelData);
        return true;
    }

    /**
     * 流程定义列表
     */
    public PageModel<ProcessDefinitionDto> page(Integer number, Integer size) {
        if (number <= 0) {
            number = 1;
        }
        number -= 1;
        ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list = definitionQuery.orderByProcessDefinitionId().desc().listPage(number * size, size);
        long count = definitionQuery.count();
        List<ProcessDefinitionDto> dtos = new ArrayList<>();
        for (ProcessDefinition v : list) {
            dtos.add(ProcessDefinitionDto.builder()
                    .id(v.getId()).name(v.getName()).key(v.getKey())
                    .deploymentId(v.getDeploymentId()).description(v.getDescription())
                    .resourceName(v.getResourceName()).version(v.getVersion())
                    .build());
        }
        return PageModel.<ProcessDefinitionDto>builder()
                .number(number + 1).size(size)
                .content(dtos).count((int) count)
                .build();
    }

    public List<ProcessDefinitionDto> list() {
        ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list = definitionQuery.list();
        List<ProcessDefinitionDto> dtos = new ArrayList<>();
        for (ProcessDefinition v : list) {
            dtos.add(ProcessDefinitionDto.builder()
                    .id(v.getId()).name(v.getName()).key(v.getKey())
                    .deploymentId(v.getDeploymentId()).description(v.getDescription())
                    .resourceName(v.getResourceName()).version(v.getVersion())
                    .build());
        }
        return dtos;
    }

    /**
     * 删除流程模型
     */
    public Boolean deleteModel(String modelId) {
        repositoryService.deleteModel(modelId);
        return true;
    }

    /**
     * 流程模型列表
     */
    public PageModel<ModelDto> modelPage(Integer number, Integer size) {
        if (number <= 0) {
            number = 1;
        }
        number -= 1;
        ModelQuery modelQuery = repositoryService.createModelQuery();
        long count = modelQuery.count();
        List<Model> models = modelQuery.listPage(number, size);
        List<ModelDto> dtos = new ArrayList<>();
        for (Model v : models) {
            dtos.add(ModelDto.builder()
                    .id(v.getId()).name(v.getName()).key(v.getKey())
                    .deploymentId(v.getDeploymentId()).metaInfo(v.getMetaInfo())
                    .build());
        }
        return PageModel.<ModelDto>builder()
                .number(number + 1).size(size)
                .content(dtos).count((int) count)
                .build();
    }

}
